package es2.learning.bloom;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import es2.common.Mesh;
import es2.common.Utils;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;


/***
 * Render To Texture (RTT)
 * ***********************
 * 1) Create FBO
 * 2) Generate POT Texture
 * 3) Render scene to FBO
 * 4) Render final scene with texture generated by FBO
 */


public class RTTRenderer implements Renderer {

	GLSurfaceView curView;	
	FBORenderer fbor;
	int iProgId;
	int iPosition;
	int iTexCoords;
	int iTexLoc;
	int iTexLoc1;
	int iTexLoc2;
	int iTexId;
	int iMVPMat;
	
	int iTexRTT;
	
	int fboId;
	
	float[] m_fModel = new float[16];
	float[] m_fView = new float[16];
	float[] m_fProj = new float[16];
	float[] m_fVPMat = new float[16];
	float[] m_fMVPMat = new float[16];
	
	float xAngle = 0;
	float yAngle = 0;
	
	FloatBuffer vertexBuffer;
	FloatBuffer texBuffer;
	FloatBuffer normalBuffer;
	ShortBuffer indexBuffer;
	
	FloatBuffer vertexBuffer1, texBuffer1;
	
	final float[] COORDS = {
			-4f, -4f, //bottom - left
			4f, -4f, //bottom - right
			-4f, 4f, //top - left
			4f, 4f //top - right
		};
		
		final float[] TEX_COORDS = {
			0, 1, //bottom - left
			1, 1, // bottom - right		
			0, 0, // top - left
			1, 0 // top - right
		};
	
	int vwidth;
	int vheight;
	
	Mesh cube;
	
	
	public RTTRenderer(GLSurfaceView view) {
		curView = view;
		
		fbor = new FBORenderer(view );
		
		cube = new Mesh();
		cube.Cube(4);
		
		vertexBuffer = cube.getVertexBuffer();
		texBuffer = cube.getTextureBuffer();
		normalBuffer = cube.getNormalsBuffer();
		indexBuffer = cube.getIndecesBuffer();
		
	}

	@Override
	public void onDrawFrame(GL10 arg0) {		
		long c_Time = System.currentTimeMillis();
		fbor.RenderGaussianBlur();
		
		SetProjection(vwidth,vheight);

		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);
		
		GLES20.glUseProgram(iProgId);
		
		vertexBuffer.position(0);
		GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(iPosition);
		
		texBuffer.position(0);
		GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 0, texBuffer);
		GLES20.glEnableVertexAttribArray(iTexCoords);
		
		GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboId);
		GLES20.glUniform1i(iTexLoc, 0);
		
		GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexRTT);
		GLES20.glUniform1i(iTexLoc1, 1);
		
		GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexId);
		GLES20.glUniform1i(iTexLoc2, 2);
		
		Matrix.setIdentityM(m_fModel, 0);
		Matrix.rotateM(m_fModel, 0, -xAngle, 0, 1, 0);
		Matrix.rotateM(m_fModel, 0, -yAngle, 1, 0, 0);
		
		Matrix.multiplyMM(m_fMVPMat, 0, m_fVPMat, 0, m_fModel, 0);
		
		GLES20.glUniformMatrix4fv(iMVPMat, 1, false, m_fMVPMat, 0);
		
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, cube.m_nIndeces, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
		
		Log.d("Gaussian Blur", "Time for Draw"+(System.currentTimeMillis()-c_Time)/1000f);

	}

	public void SetProjection(int width, int height)
	{
		GLES20.glViewport(0, 0, width, height);
		float ratio = (float)width/(float)height;
		float a = 5f;
		Matrix.orthoM(m_fProj, 0, -a*ratio, a*ratio, -a*ratio, a*ratio, 1, 10);
		
		Matrix.multiplyMM(m_fVPMat, 0, m_fProj, 0, m_fView, 0);
	}
	
	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
		vwidth = width;
		vheight = height;

		SetProjection(width,height);
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		GLES20.glClearColor(0, 0, 0, 1);
		GLES20.glEnable(GLES20.GL_DEPTH_TEST);
		GLES20.glDepthFunc(GLES20.GL_LEQUAL);
		GLES20.glFrontFace(GLES20.GL_CCW);
		GLES20.glEnable(GLES20.GL_CULL_FACE);
		GLES20.glCullFace(GLES20.GL_BACK);
		
		Matrix.setLookAtM(m_fView, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0);
		iTexRTT = -1;
		int []ret = new int[2];
		ret = fbor.CreateFrameBuffers();
		fboId = ret[0];
		iTexRTT = ret[1];
		
		String strVShader = 
			    "attribute vec4 a_position;" +
			    "attribute vec2 a_texCoords;" +
			    "uniform mat4 u_mvpMatrix;"+
			    "varying vec2 v_texCoords;" +
				"void main()" +
				"{" +
				    "gl_Position = u_mvpMatrix * a_position;" +
				    "v_texCoords = a_texCoords;" +
				"}";
		
		String strFShader = 
				"precision mediump float;" +
				"varying vec2 v_texCoords;" +
				"uniform sampler2D u_texId;" +				
				"uniform sampler2D u_texId1;" +
				"uniform sampler2D u_texId2;" +
				"void main()" +
				"{" +
					"vec4 src = texture2D(u_texId, v_texCoords);" +
					"vec4 dst = texture2D(u_texId1, v_texCoords);" +
					//"gl_FragColor = dst;"+
					//"gl_FragColor = max(src, dst);"+
					"vec4 bloomcolor = clamp((src + dst) - (src * dst), 0.0, 1.0);" +
					"gl_FragColor = bloomcolor + texture2D(u_texId2, v_texCoords);" +
					"gl_FragColor.a = 1.0;"+
				"}";

		iProgId = Utils.LoadProgram(strVShader, strFShader);
		iPosition = GLES20.glGetAttribLocation(iProgId, "a_position");
		iTexCoords = GLES20.glGetAttribLocation(iProgId, "a_texCoords");
		iTexLoc = GLES20.glGetUniformLocation(iProgId, "u_texId");
		iTexLoc1 = GLES20.glGetUniformLocation(iProgId, "u_texId1");
		iTexLoc2 = GLES20.glGetUniformLocation(iProgId, "u_texId2");
		iMVPMat = GLES20.glGetUniformLocation(iProgId, "u_mvpMatrix");
		
		fbor.LoadShaders();
		
		iTexId = Utils.LoadTexture(curView, "thick_gold_frame.png");
	}

}
